home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / PowerPlant / LPasswordField 1.0a / LPasswordField.cp < prev    next >
Encoding:
Text File  |  1996-05-05  |  30.2 KB  |  1,345 lines  |  [TEXT/R*ch]

  1. /*    NAME:
  2.         LPasswordField.cp
  3.  
  4.     WRITTEN BY:
  5.         Dair Grant, dair@kagi.com, http://www.kagi.com/authors/dair
  6.                 
  7.     DESCRIPTION:
  8.         A Pane containing editable text, which only displays bullet characters.
  9.         
  10.         Use an LPasswordField for small amounts of monstyled text, such as a
  11.         text entry field in a dialog box. PasswordField derives from the
  12.         LEditField class, so similar restrictions apply to its usage (it uses
  13.         TextEdit, and it's not a View, so you can't put a PasswordField in a
  14.         Scroller).
  15.         
  16.         PasswordFields should behave *exactly* like EditFields, the only
  17.         difference being that characters are always displayed as bullets.
  18.         You use the same routines (SetDescriptor/GetDescriptor and SetValue/
  19.         GetValue) to manipulate the text, and the same commands can be
  20.         performed on it (cut, copy, paste, etc). The PasswordField takes
  21.         care of ensuring that only bullets are ever displayed.
  22.         
  23.         The bullet character defaults to '•'. The SetBullet method allows
  24.         this to be changed.
  25.         
  26.         To use a PasswordField, create and position an EditField with
  27.         Constructor, and set the class ID to 'pass' once you're happy with
  28.         it. Then include LPasswordField.h in the relevent source files,
  29.         add LPasswordField.cp to your project, and put the line
  30.         
  31.             URegistrar::RegisterClass(LPasswordField::class_ID,
  32.                                         LPasswordField::CreatePasswordFieldStream);
  33.  
  34.         in your application's constructor.
  35.         
  36.         You may use the LPasswordField class in any project you write,
  37.         without restriction. Comments, bugs, or suggestions are more than
  38.         welcome - send them to dair@kagi.com.
  39.         
  40.     ___________________________________________________________________________
  41. */
  42. //=============================================================================
  43. //        Include files
  44. //-----------------------------------------------------------------------------
  45. #ifdef PowerPlant_PCH
  46. #include PowerPlant_PCH
  47. #endif
  48.  
  49. #include <Scrap.h>
  50. #include <Script.h>
  51. #include <TextEdit.h>
  52. #include <ToolUtils.h>
  53.  
  54. #include <LCommander.h>
  55. #include <LEditField.h>
  56. #include <LPane.h>
  57. #include <LPasswordField.h>
  58. #include <LStream.h>
  59. #include <PP_KeyCodes.h>
  60. #include <PP_Messages.h>
  61. #include <UDrawingState.h>
  62. #include <UKeyFilters.h>
  63. #include <UTETextAction.h>
  64. #include <UTextTraits.h>
  65.  
  66.  
  67.  
  68.  
  69.  
  70.  
  71.  
  72.  
  73.  
  74.  
  75.  
  76.  
  77.  
  78.  
  79.  
  80. //=============================================================================
  81. //        Private defines
  82. //-----------------------------------------------------------------------------
  83. #define kHiddenTEOffset                5000            // Offset for hidden TE record
  84.  
  85.  
  86.  
  87.  
  88.  
  89.  
  90.  
  91.  
  92.  
  93.  
  94.  
  95.  
  96.  
  97.  
  98.  
  99. //=============================================================================
  100. //        LPasswordField::CreatePasswordFieldStream
  101. //-----------------------------------------------------------------------------
  102. //        Create a new PasswordField object from the data in a Stream.
  103. //-----------------------------------------------------------------------------
  104. LPasswordField *LPasswordField::CreatePasswordFieldStream(LStream *inStream)
  105. {
  106.     return (new LPasswordField(inStream));
  107. }
  108.  
  109.  
  110.  
  111.  
  112.  
  113.  
  114.  
  115.  
  116.  
  117.  
  118.  
  119.  
  120.  
  121.  
  122.  
  123. //=============================================================================
  124. //        LPasswordField::LPasswordField
  125. //-----------------------------------------------------------------------------
  126. //        Default constructor.
  127. //-----------------------------------------------------------------------------
  128. LPasswordField::LPasswordField() : LEditField()
  129. {
  130.     InitPassField(editAttr_Box);
  131. }
  132.  
  133.  
  134.  
  135.  
  136.  
  137.  
  138.  
  139.  
  140.  
  141.  
  142.  
  143.  
  144.  
  145.  
  146.  
  147. //=============================================================================
  148. //        LPasswordField::LPasswordField
  149. //-----------------------------------------------------------------------------
  150. //        Copy constructor.
  151. //-----------------------------------------------------------------------------
  152. LPasswordField::LPasswordField(const LPasswordField    &inOriginal) : LEditField(inOriginal)
  153. {    Rect        viewRect = {0, 0, 0, 0};
  154.     Str255        theStr;
  155.  
  156.  
  157.  
  158.     // The LEditField constructor will have build our mTextEditH member.
  159.     // We move it somewhere off screen so it won't be visible.
  160.     ::OffsetRect(&(*mTextEditH)->viewRect, kHiddenTEOffset, kHiddenTEOffset);
  161.  
  162.  
  163.     // Create the 'bullet' TextEdit record    
  164.     mBulletTextEditH = ::TENew(&viewRect, &viewRect);
  165.  
  166.  
  167.     // Set our descriptor correctly    and align everything correctly
  168.     SetDescriptor(inOriginal.GetDescriptor(theStr));
  169.     AlignTextEditRects();
  170. }
  171.  
  172.  
  173.  
  174.  
  175.  
  176.  
  177.  
  178.  
  179.  
  180.  
  181.  
  182.  
  183.  
  184.  
  185.  
  186. //=============================================================================
  187. //        LPasswordField::LPasswordField
  188. //-----------------------------------------------------------------------------
  189. //        Construct from input parameters.
  190. //-----------------------------------------------------------------------------
  191. LPasswordField::LPasswordField(const    SPaneInfo    &inPaneInfo,
  192.                                         Str255            inString,
  193.                                         ResIDT            inTextTraitsID,
  194.                                         Int16            inMaxChars,
  195.                                         Boolean            inHasBox,
  196.                                         Boolean            inHasWordWrap,
  197.                                         KeyFilterFunc    inKeyFilter,
  198.                                         LCommander        *inSuper) :
  199.                 LEditField(inPaneInfo, inString, inTextTraitsID, inMaxChars,
  200.                             inHasBox, inHasWordWrap, inKeyFilter, inSuper)
  201. {    Uint8        attributes = 0;
  202.  
  203.  
  204.  
  205.     // Set our attributes, then initialise ourself with them
  206.     if (inHasBox)
  207.         attributes += editAttr_Box;
  208.     if (inHasWordWrap)
  209.         attributes += editAttr_WordWrap;
  210.     InitPassField(attributes);
  211.  
  212.  
  213.     // If we've been given a string, put it into the visible
  214.     // TextEdit record and convert it to bullets
  215.     if (inString[0] > 0)
  216.         {
  217.         ::TESetText(inString + 1, inString[0], mBulletTextEditH);
  218.         SetTextToBullets(mBulletTextEditH);
  219.         }
  220.  
  221.  
  222.     // Align the TextEdit records and select the text, if any
  223.     AlignTextEditRects();
  224.     SelectAll();
  225. }
  226.  
  227.  
  228.  
  229.  
  230.  
  231.  
  232.  
  233.  
  234.  
  235.  
  236.  
  237.  
  238.  
  239.  
  240.  
  241. //=============================================================================
  242. //        LPasswordField::LPasswordField
  243. //-----------------------------------------------------------------------------
  244. //        Construct from input parameters.
  245. //-----------------------------------------------------------------------------
  246. LPasswordField::LPasswordField(const    SPaneInfo    &inPaneInfo,
  247.                                         Str255            inString,
  248.                                         ResIDT            inTextTraitsID,
  249.                                         Int16            inMaxChars,
  250.                                         Uint8            inAttributes,
  251.                                         KeyFilterFunc    inKeyFilter,
  252.                                         LCommander        *inSuper) :
  253.                 LEditField(inPaneInfo, inString, inTextTraitsID, inMaxChars,
  254.                             inAttributes, inKeyFilter, inSuper)
  255. {
  256.  
  257.     // Initialise ourselves with the supplied attributes
  258.     InitPassField(inAttributes);
  259.  
  260.  
  261.     // If we've been given a string, put it into the visible
  262.     // TextEdit record and convert it to bullets
  263.     if (inString[0] > 0)
  264.         {
  265.         ::TESetText(inString + 1, inString[0], mBulletTextEditH);
  266.         SetTextToBullets(mBulletTextEditH);
  267.         }
  268.  
  269.  
  270.     // Align the TextEdit records and select the text, if any
  271.     AlignTextEditRects();
  272.     SelectAll();
  273. }
  274.  
  275.  
  276.  
  277.  
  278.  
  279.  
  280.  
  281.  
  282.  
  283.  
  284.  
  285.  
  286.  
  287.  
  288.  
  289. //=============================================================================
  290. //        LPasswordField::LPasswordField
  291. //-----------------------------------------------------------------------------
  292. //        Construct from the data in a stream.
  293. //-----------------------------------------------------------------------------
  294. LPasswordField::LPasswordField(LStream *inStream) : LEditField(inStream)
  295. {    Uint8        attributes = 0;
  296.  
  297.  
  298.  
  299.     // The LEditField constructor has built itself from the data in
  300.     // inStream, but didn't save the attributes away anywhere. We
  301.     // have to recreate the attributes ourselves by hand.
  302.     if (mHasBox)
  303.         attributes |= editAttr_Box;
  304.  
  305.     if (mHasWordWrap)
  306.         attributes |= editAttr_WordWrap;
  307.     
  308.     if (TEFeatureFlag(teFAutoScr, teBitTest, mTextEditH) == teBitSet)
  309.         attributes |= editAttr_AutoScroll;
  310.  
  311.     if (TEFeatureFlag(teFTextBuffering, teBitTest, mTextEditH) == teBitSet)
  312.         attributes |= editAttr_TextBuffer;
  313.  
  314.     if (TEFeatureFlag(teFOutlineHilite, teBitTest, mTextEditH) == teBitSet)
  315.         attributes |= editAttr_OutlineHilite;
  316.  
  317.     if (TEFeatureFlag(teFInlineInput, teBitTest, mTextEditH) == teBitSet)
  318.         attributes |= editAttr_InlineInput;
  319.  
  320.     if (TEFeatureFlag(teFUseTextServices, teBitTest, mTextEditH) == teBitSet)
  321.         attributes |= editAttr_TextServices;
  322.  
  323.  
  324.  
  325.     // Initialise ourselves from these attributes
  326.     InitPassField(attributes);
  327.  
  328.  
  329.     // Set the visible TextEdit record to match the hidden one
  330.     SetVisibleFromHidden();
  331.  
  332.  
  333.     // Align the TextEdit records and select the text, if any
  334.     AlignTextEditRects();
  335.     SelectAll();
  336. }
  337.  
  338.  
  339.  
  340.  
  341.  
  342.  
  343.  
  344.  
  345.  
  346.  
  347.  
  348.  
  349.  
  350.  
  351.  
  352. //=============================================================================
  353. //        LPasswordField::InitPassField
  354. //-----------------------------------------------------------------------------
  355. //        Initialise the member variables of a PassField.
  356. //
  357. //        We also fudge some of the things our parent (LEditField) set up
  358. //        earlier.
  359. //-----------------------------------------------------------------------------
  360. void LPasswordField::InitPassField(Uint8 inAttributes)
  361. {    Rect        viewRect = {0, 0, 0, 0};
  362.  
  363.  
  364.  
  365.     // The LEditField constructor will have build our mTextEditH member.
  366.     // We move it somewhere off screen so it won't be visible.
  367.     OffsetRect(&(*mTextEditH)->viewRect, kHiddenTEOffset, kHiddenTEOffset);
  368.  
  369.  
  370.     // Set the focus to be ourselves, rather than the EditField
  371.     StFocusAndClipIfHidden    focus(this);
  372.  
  373.  
  374.  
  375.     // Initialise our internal variables    
  376.     mBulletTextEditH    = ::TENew(&viewRect, &viewRect);
  377.     mBullet                = '•';
  378.  
  379.  
  380.  
  381.     // Set the optional features for the TextEdit field    
  382.     ::TEFeatureFlag(teFAutoScr,
  383.             ((inAttributes & editAttr_AutoScroll) != 0) ?
  384.                 teBitSet : teBitClear, mBulletTextEditH);
  385.  
  386.     ::TEFeatureFlag(teFTextBuffering,
  387.             ((inAttributes & editAttr_TextBuffer) != 0) ?
  388.                 teBitSet : teBitClear, mBulletTextEditH);
  389.  
  390.     ::TEFeatureFlag(teFOutlineHilite,
  391.             ((inAttributes & editAttr_OutlineHilite) != 0) ?
  392.                 teBitSet : teBitClear, mBulletTextEditH);
  393.  
  394.     ::TEFeatureFlag(teFInlineInput,
  395.             ((inAttributes & editAttr_InlineInput) != 0) ?
  396.                 teBitSet : teBitClear, mBulletTextEditH);
  397.  
  398.     ::TEFeatureFlag(teFUseTextServices,
  399.             ((inAttributes & editAttr_TextServices) != 0) ?
  400.                 teBitSet : teBitClear, mBulletTextEditH);
  401. }
  402.  
  403.  
  404.  
  405.  
  406.  
  407.  
  408.  
  409.  
  410.  
  411.  
  412.  
  413.  
  414.  
  415.  
  416.  
  417. //=============================================================================
  418. //        LPasswordField::~LPasswordField
  419. //-----------------------------------------------------------------------------
  420. //        Destructor
  421. //-----------------------------------------------------------------------------
  422. LPasswordField::~LPasswordField()
  423. {
  424.     if (mBulletTextEditH != nil)
  425.         ::TEDispose(mBulletTextEditH);
  426. }
  427.  
  428.  
  429.  
  430.  
  431.  
  432.  
  433.  
  434.  
  435.  
  436.  
  437.  
  438.  
  439.  
  440.  
  441.  
  442. //=============================================================================
  443. //        LPasswordField::SetDescriptor
  444. //-----------------------------------------------------------------------------
  445. //        Set the contents of a PasswordField from a Pascal string.
  446. //
  447. //        We call our parent class to set the text of the offscreen item
  448. //        correctly, then resynch the visible field.
  449. //-----------------------------------------------------------------------------
  450. void LPasswordField::SetDescriptor(ConstStr255Param inDescriptor)
  451. {
  452.  
  453.     // Call our parent class
  454.     LEditField::SetDescriptor(inDescriptor);
  455.  
  456.  
  457.     // Resynch the visible field, and redraw    
  458.     SetVisibleFromHidden();
  459.     Refresh();
  460. }
  461.  
  462.  
  463.  
  464.  
  465.  
  466.  
  467.  
  468.  
  469.  
  470.  
  471.  
  472.  
  473.  
  474.  
  475.  
  476. //=============================================================================
  477. //        LPasswordField::SetBullet
  478. //-----------------------------------------------------------------------------
  479. //        Set the bullet character to be used.
  480. //-----------------------------------------------------------------------------
  481. void LPasswordField::SetBullet(Int16 inBullet)
  482. {
  483.     mBullet = inBullet;
  484.     Refresh();
  485. }
  486.  
  487.  
  488.  
  489.  
  490.  
  491.  
  492.  
  493.  
  494.  
  495.  
  496.  
  497.  
  498.  
  499.  
  500.  
  501. //=============================================================================
  502. //        LPasswordField::SetTextTraitsID
  503. //-----------------------------------------------------------------------------
  504. //        Set the text traits of the PasswordField.
  505. //-----------------------------------------------------------------------------
  506. void LPasswordField::SetTextTraitsID(ResIDT inTextTraitsID)
  507. {
  508.     // Call our parent class for the off screen TextEdit record
  509.     LEditField::SetTextTraitsID(inTextTraitsID);
  510.  
  511.     // Set the visible TextEdit record
  512.     UTextTraits::SetTETextTraits(mTextTraitsID, mBulletTextEditH);
  513. }
  514.  
  515.  
  516.  
  517.  
  518.  
  519.  
  520.  
  521.  
  522.  
  523.  
  524.  
  525.  
  526.  
  527.  
  528.  
  529. //=============================================================================
  530. //        LPasswordField::DrawSelf
  531. //-----------------------------------------------------------------------------
  532. //        Draw a PasswordField.
  533. //-----------------------------------------------------------------------------
  534. void LPasswordField::DrawSelf()
  535. {    Rect        frame;
  536.  
  537.  
  538.     // Calculate the local frame rectangle
  539.     CalcLocalFrameRect(frame);
  540.  
  541.  
  542.     // Draw a border if necessary    
  543.     if (mHasBox)
  544.         {
  545.         DrawBox();
  546.         ::InsetRect(&frame, 2, 2);
  547.         }
  548.  
  549.  
  550.     // A Mac TERec stores a pointer to its owner port  We have to
  551.     // change it to the current port in case we are drawing into
  552.     // a port that is not the owner port. This happens when we are
  553.     // printing or drawing into an offscreen port.
  554.     GrafPtr    savePort = (**mBulletTextEditH).inPort;
  555.     (**mBulletTextEditH).inPort = UQDGlobals::GetCurrentPort();
  556.  
  557.     ::TEUpdate(&frame, mBulletTextEditH);
  558.     
  559.     (**mBulletTextEditH).inPort = savePort;
  560. }
  561.  
  562.  
  563.  
  564.  
  565.  
  566.  
  567.  
  568.  
  569.  
  570.  
  571.  
  572.  
  573.  
  574.  
  575.  
  576. //=============================================================================
  577. //        LPasswordField::ClickSelf
  578. //-----------------------------------------------------------------------------
  579. //        Respond to clicks inside a PasswordField.
  580. //-----------------------------------------------------------------------------
  581. void LPasswordField::ClickSelf(const SMouseDownEvent &inMouseDown)
  582. {
  583.  
  584.     // If we're not the target, then clicking in us makes us
  585.     // the target. Since TEClick will set a new selection
  586.     // ragen, we clear the current selection range to avoid
  587.     // an ugly flash.
  588.     if (!IsTarget())
  589.         {
  590.         ::TESetSelect(0, 0, mTextEditH);
  591.         ::TESetSelect(0, 0, mBulletTextEditH);
  592.         SwitchTarget(this);
  593.         }
  594.  
  595.  
  596.     // If we're the target, handle the click with TextEdit    
  597.     if (IsTarget())
  598.         {
  599.         FocusDraw();
  600.         AdjustTextWidth(true);
  601.         ::TEClick(inMouseDown.whereLocal,
  602.                     ((inMouseDown.macEvent.modifiers & shiftKey) != 0),
  603.                     mBulletTextEditH);
  604.  
  605.  
  606.         // Since TEClick holds on to the mouse until the user lets go,
  607.         // we need to manually match up the selection of the hidden
  608.         // TextEdit record to that of the visible one.
  609.         (*mTextEditH)->selStart    = (*mBulletTextEditH)->selStart;
  610.         (*mTextEditH)->selEnd    = (*mBulletTextEditH)->selEnd;
  611.         AdjustTextWidth(false);
  612.     }
  613. }
  614.  
  615.  
  616.  
  617.  
  618.  
  619.  
  620.  
  621.  
  622.  
  623.  
  624.  
  625.  
  626.  
  627.  
  628.  
  629. //=============================================================================
  630. //        LPasswordField::ObeyCommand
  631. //-----------------------------------------------------------------------------
  632. //        Handle standard editing commands.
  633. //-----------------------------------------------------------------------------
  634. Boolean LPasswordField::ObeyCommand(CommandT inCommand, void *ioParam)
  635. {    Boolean            cmdHandled = true;
  636.     Int32            offset;
  637.             
  638.  
  639.  
  640.     // Case out on the command    
  641.     switch (inCommand) {
  642.         case cmd_Cut:
  643.             ::TECut(mTextEditH);
  644.             PostAction(new LTECutAction(mBulletTextEditH, this, this));
  645.             break;
  646.  
  647.  
  648.         case cmd_Copy:
  649.             ::TECopy(mBulletTextEditH);
  650.             ::ZeroScrap();
  651.             ::TEToScrap();
  652.             break;
  653.  
  654.  
  655.         case cmd_Paste:
  656.             // If pasting would exceed the maximum field size, we beep
  657.             if (TooManyCharacters(::GetScrap(nil, 'TEXT', &offset)))
  658.                 ::SysBeep(30);
  659.             
  660.             
  661.             // Otherwise, past it in to both records. We need to move
  662.             // the visible TextEdit record off screen while pasting,
  663.             // since we need to munge the characters to bullets after
  664.             // they've been pasted in.
  665.             else
  666.                 {
  667.                 // Paste it into the off screen record
  668.                 PostAction(new LTEPasteAction(mTextEditH, this, this));
  669.  
  670.                 // Move the visible text record off the screen
  671.                 OffsetRect(&(*mBulletTextEditH)->viewRect, 5000, 5000);
  672.  
  673.                 // Paste in the text, and convert it to bullets
  674.                 PostAction(new LTEPasteAction(mBulletTextEditH, this, this));
  675.                 SetTextToBullets(mBulletTextEditH);
  676.             
  677.                 // Move the visible text record back onto the screen and redraw
  678.                 OffsetRect(&(*mBulletTextEditH)->viewRect, -5000, -5000);
  679.                 AlignTextEditRects();
  680.                 Refresh();
  681.                 }
  682.             break;
  683.  
  684.  
  685.         case cmd_Clear:
  686.             ::TEDelete(mTextEditH);
  687.             PostAction(new LTEClearAction(mBulletTextEditH, this, this));
  688.             break;
  689.  
  690.  
  691.         default:
  692.             // Our parent is an LEditField, not an LCommander
  693.             cmdHandled = LEditField::ObeyCommand(inCommand, ioParam);
  694.             break;
  695.         }
  696.     
  697.     
  698.     // Return as the command was handled or not
  699.     return cmdHandled;
  700. }
  701.  
  702.  
  703.  
  704.  
  705.  
  706.  
  707.  
  708.  
  709.  
  710.  
  711.  
  712.  
  713.  
  714.  
  715.  
  716. //=============================================================================
  717. //        LPasswordField::FindCommandStatus
  718. //-----------------------------------------------------------------------------
  719. //        Pass back the status of a command.
  720. //
  721. //        We don't *really* need to override this, since all of our commands
  722. //        are tied to the current selection (which should be the same in
  723. //        both the visible and off screen TextEdit records).
  724. //
  725. //        But, we override just to make sure we can get the behaviour we want.
  726. //-----------------------------------------------------------------------------
  727. void LPasswordField::FindCommandStatus(CommandT            inCommand,
  728.                                             Boolean        &outEnabled,
  729.                                             Boolean        &outUsesMark,
  730.                                             Char16        &outMark,
  731.                                             Str255        outName)
  732. {
  733.  
  734.  
  735.     // Case out on the command
  736.     switch (inCommand) {
  737.         case cmd_Cut:
  738.         case cmd_Copy:
  739.         case cmd_Clear:
  740.             // Cut, copy, and clear are enabled if something is selected
  741.             outEnabled = ((**mBulletTextEditH).selStart != (**mBulletTextEditH).selEnd);
  742.             break;
  743.  
  744.  
  745.         case cmd_SelectAll:
  746.             // We can only select everything if there's something to select
  747.             outEnabled = (**mBulletTextEditH).teLength > 0;
  748.             break;
  749.  
  750.  
  751.         default:
  752.             // Pass it to the LEditField if it's anything else
  753.             LEditField::FindCommandStatus(inCommand, outEnabled, outUsesMark, outMark, outName);
  754.             break;
  755.         }
  756. }
  757.  
  758.  
  759.  
  760.  
  761.  
  762.  
  763.  
  764.  
  765.  
  766.  
  767.  
  768.  
  769.  
  770.  
  771.  
  772. //=============================================================================
  773. //        LPasswordField::HandleKeyPress
  774. //-----------------------------------------------------------------------------
  775. //        Handle a key stroke directed at a PasswordField.
  776. //
  777. //        We return true if we handle the keystroke.
  778. //-----------------------------------------------------------------------------
  779. Boolean LPasswordField::HandleKeyPress(const EventRecord &inKeyEvent)
  780. {    Boolean            keyHandled        = true;
  781.     EKeyStatus        theKeyStatus    = keyStatus_Input;
  782.     Int16            theKey            = inKeyEvent.message & charCodeMask;
  783.     
  784.     
  785.  
  786.     // We always pass it up when the command key is down    
  787.     if (inKeyEvent.modifiers & cmdKey)
  788.         theKeyStatus = keyStatus_PassUp;
  789.     else if (mKeyFilter != nil)
  790.         theKeyStatus = (*mKeyFilter)(inKeyEvent);
  791.  
  792.  
  793.  
  794.     // Case out on theKeyStatus
  795.     switch (theKeyStatus) {
  796.         case keyStatus_Input:
  797.             // Check to see if we're at the character limit.
  798.             // This is NOT compatible with two-byte character systems
  799.             if (TooManyCharacters(1))
  800.                 {
  801.                 SysBeep(30);
  802.                 break;
  803.                 }
  804.  
  805.             // Otherwise, put the keystroke into the real TextEdit record
  806.             TEKey(theKey, mTextEditH);
  807.                         
  808.             // Turn the key into a bullet
  809.             theKey = mBullet;
  810.  
  811.             // Put the bullet character into the visible TextEdit record
  812.             if (mTypingAction == nil)
  813.                 {
  814.                 mTypingAction = new LTETypingAction(mBulletTextEditH, this, this);
  815.                 PostAction(mTypingAction);
  816.                 }
  817.             if (mTypingAction != nil)
  818.                 mTypingAction->InputCharacter(theKey);
  819.             else
  820.                 ::TEKey(theKey, mBulletTextEditH);
  821.             UserChangedText();
  822.             break;
  823.  
  824.  
  825.         case keyStatus_TEDelete: {
  826.             if ((**mBulletTextEditH).selEnd > 0)
  827.                 {
  828.                 // Do it to the hidden text edit field
  829.                 ::TEKey(char_Backspace, mTextEditH);
  830.  
  831.                 // Do it to the visible text edit field
  832.                 if (mTypingAction == nil)
  833.                     {
  834.                     mTypingAction = new LTETypingAction(mBulletTextEditH, this, this);
  835.                     PostAction(mTypingAction);
  836.                     }
  837.                 if (mTypingAction != nil)
  838.                     mTypingAction->BackwardErase();
  839.                 else
  840.                     ::TEKey(char_Backspace, mBulletTextEditH);
  841.                 UserChangedText();
  842.                 }
  843.             break; }
  844.  
  845.  
  846.         case keyStatus_TECursor: {
  847.             StFocusAndClipIfHidden    teCursorFocus(this);
  848.             ::TEKey(theKey, mTextEditH);
  849.             ::TEKey(theKey, mBulletTextEditH);
  850.             break; }
  851.  
  852.  
  853.         case keyStatus_ExtraEdit: {
  854.             StFocusAndClipIfHidden    extraEditFocus(this);
  855.             switch (theKey) {            
  856.                 case char_Home:
  857.                     ::TESetSelect(0, 0, mTextEditH);
  858.                     ::TESetSelect(0, 0, mBulletTextEditH);
  859.                     break;
  860.                     
  861.                     
  862.                 case char_End:
  863.                     ::TESetSelect(max_Int16, max_Int16, mTextEditH);
  864.                     ::TESetSelect(max_Int16, max_Int16, mBulletTextEditH);
  865.                     break;
  866.                     
  867.                     
  868.                 case char_FwdDelete:
  869.                     if ((**mBulletTextEditH).selStart < (**mBulletTextEditH).teLength)
  870.                         {
  871.                         // Do it to the hidden record
  872.                         if ((**mTextEditH).selStart == (**mTextEditH).selEnd)
  873.                             ::TESetSelect((**mTextEditH).selStart,
  874.                                             (**mTextEditH).selStart + 1,
  875.                                             mTextEditH);
  876.                         ::TEDelete(mTextEditH);
  877.                         
  878.                         
  879.                         // Do it to the visible record
  880.                         if (mTypingAction == nil)
  881.                             {
  882.                             mTypingAction = new LTETypingAction(mBulletTextEditH, this, this);
  883.                             PostAction(mTypingAction);
  884.                             }
  885.                         if (mTypingAction != nil)
  886.                             mTypingAction->ForwardErase();
  887.                         else
  888.                             if ((**mBulletTextEditH).selStart == (**mBulletTextEditH).selEnd)
  889.                                 ::TESetSelect((**mBulletTextEditH).selStart,
  890.                                                 (**mBulletTextEditH).selStart + 1,
  891.                                                 mTextEditH);
  892.                             ::TEDelete(mTextEditH);
  893.                         UserChangedText();
  894.                         }
  895.                     break;
  896.                     
  897.                     
  898.                 default:
  899.                     keyHandled = LEditField::HandleKeyPress(inKeyEvent);
  900.                     break;
  901.                 }
  902.             break; }
  903.         
  904.  
  905.         case keyStatus_Reject:
  906.             // Can do something with rejected keystrokes here
  907.             SysBeep(30);
  908.             break;
  909.  
  910.  
  911.         case keyStatus_PassUp:
  912.             keyHandled = LEditField::HandleKeyPress(inKeyEvent);
  913.             break;
  914.         }
  915.  
  916.  
  917.  
  918.     // Return as the keystroke was handled or not
  919.     return(keyHandled);
  920. }
  921.  
  922.  
  923.  
  924.  
  925.  
  926.  
  927.  
  928.  
  929.  
  930.  
  931.  
  932.  
  933.  
  934.  
  935.  
  936. //=============================================================================
  937. //        LPasswordField::SelectAll
  938. //-----------------------------------------------------------------------------
  939. //        Select the entire contents of a PasswordField.
  940. //-----------------------------------------------------------------------------
  941. void LPasswordField::SelectAll()
  942. {
  943.  
  944.     // Call our parent class
  945.     LEditField::SelectAll();
  946.     
  947.     
  948.     // Select the visible TextEdit record
  949.     StFocusAndClipIfHidden    focus(this);
  950.     ::TESetSelect(0, max_Int16, mBulletTextEditH);
  951. }
  952.  
  953.  
  954.  
  955.  
  956.  
  957.  
  958.  
  959.  
  960.  
  961.  
  962.  
  963.  
  964.  
  965.  
  966.  
  967. //=============================================================================
  968. //        LPasswordField::AlignTextEditRects
  969. //-----------------------------------------------------------------------------
  970. //        Align the view and destination rectangles of the Toolbox TextEdit
  971. //        records with the Frame of a PasswordField.
  972. //-----------------------------------------------------------------------------
  973. void LPasswordField::AlignTextEditRects()
  974. {    Rect    textFrame;
  975.  
  976.  
  977.  
  978.     // If the Frame is outside QuickDraw space, we put textFrame at
  979.     // the upper left limit of QuickDraw space (extreme negative
  980.     // coordinates). That location is gauranteed to be offscreen
  981.     // (unless you have a control longer than 32K pixels). since
  982.     // PowerPlant Image coordinates start at (0, 0) and are never
  983.     // negative.
  984.     if (!CalcLocalFrameRect(textFrame))
  985.         {
  986.         textFrame.left        = min_Int16;
  987.         textFrame.right        = textFrame.left + mFrameSize.width;
  988.         textFrame.top        = min_Int16;
  989.         textFrame.bottom    = textFrame.top + mFrameSize.height;
  990.         }
  991.  
  992.  
  993.     // If we have a box, move in past it    
  994.     if (mHasBox)
  995.         ::InsetRect(&textFrame, 2, 2);
  996.  
  997.  
  998.     // Set the TextEdit view and destination rectangles to be the
  999.     // same as the Frame. We do *not* set the viewRect of the
  1000.     // mTextEditH TextEdit record, since that's what's keeping it
  1001.     // off screen and out of the way.
  1002. //    (**mTextEditH).viewRect            = textFrame;
  1003.     (**mTextEditH).destRect            = textFrame;
  1004.     (**mBulletTextEditH).viewRect    = textFrame;
  1005.     (**mBulletTextEditH).destRect    = textFrame;
  1006.     AdjustTextWidth(false);
  1007.  
  1008.  
  1009.     // Let TextEdit adjust the line breaks
  1010.     ::TECalText(mTextEditH);
  1011.     ::TECalText(mBulletTextEditH);
  1012. }
  1013.  
  1014.  
  1015.  
  1016.  
  1017.  
  1018.  
  1019.  
  1020.  
  1021.  
  1022.  
  1023.  
  1024.  
  1025.  
  1026.  
  1027.  
  1028. //=============================================================================
  1029. //        LPasswordField::AdjustTextWidth
  1030. //-----------------------------------------------------------------------------
  1031. //        Adjust the width of the destination rectangle of the Toolbox TextEdit
  1032. //        record
  1033. //
  1034. //        This function does nothing if WordWrap is ON. If WordWrap is OFF, this
  1035. //        function sets the width of the TextEdit destination rectangle to either
  1036. //        the width of the text or a very large number, depending on the value
  1037. //        of inShrinkToText.
  1038. //
  1039. //        This adjustment is needed to make autoscrolling work properly when
  1040. //        WordWrap is off. While entering text, the destination rectangle should
  1041. //        be very wide so that the text doesn't word wrap. However, while
  1042. //        clicking, it should be just as wide as the text so that the PassField
  1043. //        does not autoscroll past the edge of the text.
  1044. //-----------------------------------------------------------------------------
  1045. void LPasswordField::AdjustTextWidth(Boolean inShrinkToText)
  1046. {    Rect    textFrame;
  1047.     Int16    destWidth = 4000;        // Very Large Number
  1048.     Int16    just;
  1049.     
  1050.  
  1051.  
  1052.     // We adjust only of WordWrap is OFF
  1053.     if (!mHasWordWrap)
  1054.         {
  1055.         // Get the size of the editable text area, taking into account a box
  1056.         CalcLocalFrameRect(textFrame);
  1057.         if (mHasBox)
  1058.             ::InsetRect(&textFrame, 2, 2);
  1059.         
  1060.         
  1061.         
  1062.         // Calculate the width of the text in the PasswordField
  1063.         if (inShrinkToText)
  1064.             {
  1065.             Point    startPoint    = ::TEGetPoint(0, mBulletTextEditH);
  1066.             Point    endPoint    = ::TEGetPoint((**mBulletTextEditH).teLength, mBulletTextEditH);
  1067.             destWidth = endPoint.h - startPoint.h;
  1068.             
  1069.             if (destWidth < textFrame.right - textFrame.left)
  1070.                 destWidth = textFrame.right - textFrame.left;
  1071.             }
  1072.         
  1073.         // Direction to extend dest rect depends on the text justification
  1074.         just = (**mBulletTextEditH).just;
  1075.         if (just == teFlushDefault)
  1076.             {
  1077.             // For left justificaton, GetSysDirection returns teFlushDefault.
  1078.             // For right, it returns teFlushRight
  1079.             just = ::GetSysDirection();
  1080.             }
  1081.  
  1082.  
  1083.         // Case out on the justification        
  1084.         switch ((**mBulletTextEditH).just) {
  1085.             case teFlushLeft:
  1086.             case teFlushDefault:
  1087.                 // Text fixed on left and grows right
  1088.                 (**mBulletTextEditH).destRect.right = (**mBulletTextEditH).destRect.left + destWidth;
  1089.                 break;
  1090.  
  1091.  
  1092.             case teFlushRight:
  1093.                 // Text grows to the left
  1094.                 (**mBulletTextEditH).destRect.left = (**mBulletTextEditH).destRect.right - destWidth;
  1095.                 break;
  1096.  
  1097.  
  1098.             case teCenter:
  1099.                 // Text grows left and right
  1100.                 Int16    center = (textFrame.left + textFrame.right) / 2;
  1101.                 (**mBulletTextEditH).destRect.left = center - 2000;
  1102.                 (**mBulletTextEditH).destRect.right = center + 2000;
  1103.                 break;
  1104.             }
  1105.         }
  1106. }
  1107.  
  1108.  
  1109.  
  1110.  
  1111.  
  1112.  
  1113.  
  1114.  
  1115.  
  1116.  
  1117.  
  1118.  
  1119.  
  1120.  
  1121.  
  1122. //=============================================================================
  1123. //        LPasswordField::BeTarget
  1124. //-----------------------------------------------------------------------------
  1125. //        A PasswordField is becoming the target.
  1126. //-----------------------------------------------------------------------------
  1127. void LPasswordField::BeTarget()
  1128. {
  1129.     // Call our parent class
  1130.     LEditField::BeTarget();
  1131.  
  1132.  
  1133.     // Show the active selection
  1134.     ::TEActivate(mBulletTextEditH);
  1135. }
  1136.  
  1137.  
  1138.  
  1139.  
  1140.  
  1141.  
  1142.  
  1143.  
  1144.  
  1145.  
  1146.  
  1147.  
  1148.  
  1149.  
  1150.  
  1151. //=============================================================================
  1152. //        LPasswordField::DontBeTarget
  1153. //-----------------------------------------------------------------------------
  1154. //        PasswordField is no longet the target.
  1155. //
  1156. //        Our parent removes the PasswordField from the IdleQueue.
  1157. //-----------------------------------------------------------------------------
  1158. void LPasswordField::DontBeTarget()
  1159. {
  1160.  
  1161.     // Call our parent class
  1162.     LEditField::DontBeTarget();
  1163.  
  1164.  
  1165.     // Show the inactive selection
  1166.     ::TEDeactivate(mBulletTextEditH);
  1167. }
  1168.  
  1169.  
  1170.  
  1171.  
  1172.  
  1173.  
  1174.  
  1175.  
  1176.  
  1177.  
  1178.  
  1179.  
  1180.  
  1181.  
  1182.  
  1183. //=============================================================================
  1184. //        LPasswordField::SpendTime
  1185. //-----------------------------------------------------------------------------
  1186. //        At idle time, we flash the insertion cursor if necessary.
  1187. //-----------------------------------------------------------------------------
  1188. void LPasswordField::SpendTime(const EventRecord &inMacEvent)
  1189. {
  1190.  
  1191.     // Flash the cursor
  1192.     if (FocusExposed())
  1193.         ::TEIdle(mBulletTextEditH);
  1194. }
  1195.  
  1196.  
  1197.  
  1198.  
  1199.  
  1200.  
  1201.  
  1202.  
  1203.  
  1204.  
  1205.  
  1206.  
  1207.  
  1208.  
  1209.  
  1210. //=============================================================================
  1211. //        LPasswordField::SavePlace
  1212. //-----------------------------------------------------------------------------
  1213. //        Save the TextEdit rectangles.
  1214. //-----------------------------------------------------------------------------
  1215. void LPasswordField::SavePlace(LStream *outPlace)
  1216. {
  1217.     LPane::SavePlace(outPlace);
  1218.     
  1219.     Rect    viewRect = (**mBulletTextEditH).viewRect;
  1220.     outPlace->WriteData(&viewRect, sizeof(Rect));
  1221.  
  1222.     Rect    destRect = (**mBulletTextEditH).destRect;
  1223.     outPlace->WriteData(&destRect, sizeof(Rect));
  1224. }
  1225.  
  1226.  
  1227.  
  1228.  
  1229.  
  1230.  
  1231.  
  1232.  
  1233.  
  1234.  
  1235.  
  1236.  
  1237.  
  1238.  
  1239.  
  1240. //=============================================================================
  1241. //        LPasswordField::RestorePlace
  1242. //-----------------------------------------------------------------------------
  1243. //        Restore the TextEdit rectangles.
  1244. //-----------------------------------------------------------------------------
  1245. void LPasswordField::RestorePlace(LStream *inPlace)
  1246. {
  1247.     LPane::RestorePlace(inPlace);
  1248.  
  1249.     Rect    viewRect;
  1250.     inPlace->ReadData(&viewRect, sizeof(Rect));
  1251.     (**mBulletTextEditH).viewRect = viewRect;
  1252.  
  1253.     Rect    destRect;
  1254.     inPlace->ReadData(&destRect, sizeof(Rect));
  1255.     (**mBulletTextEditH).destRect = destRect;
  1256. }
  1257.  
  1258.  
  1259.  
  1260.  
  1261.  
  1262.  
  1263.  
  1264.  
  1265.  
  1266.  
  1267.  
  1268.  
  1269.  
  1270.  
  1271.  
  1272. //=============================================================================
  1273. //        LPasswordField::SetTextToBullets
  1274. //-----------------------------------------------------------------------------
  1275. //        Set every character in a TextEdit record to be the bullet character.
  1276. //-----------------------------------------------------------------------------
  1277. void LPasswordField::SetTextToBullets(TEHandle theTextHnd)
  1278. {    char            *theChar;
  1279.     short            i, theLen;
  1280.  
  1281.  
  1282.     // Get the text, and it's length
  1283.     theChar    = *(::TEGetText(theTextHnd));
  1284.     theLen    = (*theTextHnd)->teLength;
  1285.     
  1286.     
  1287.     // If there's no text, we're done
  1288.     if (theLen == 0)
  1289.         return;
  1290.  
  1291.  
  1292.     // Set every character to the bullet character
  1293.     for (i = 0; i < theLen; i++)
  1294.         *theChar++ = mBullet;
  1295. }
  1296.  
  1297.  
  1298.  
  1299.  
  1300.  
  1301.  
  1302.  
  1303.  
  1304.  
  1305.  
  1306.  
  1307.  
  1308.  
  1309.  
  1310.  
  1311. //=============================================================================
  1312. //        LPasswordField::SetVisibleFromHidden
  1313. //-----------------------------------------------------------------------------
  1314. //        Set every character in mBulletTextEditH to be a bullet character,
  1315. //        adjusting it's length to match mTextEditH if needs be.
  1316. //
  1317. //        mBulletTextEditH is *not* redrawn - call Refresh() after calling this
  1318. //        routine.
  1319. //-----------------------------------------------------------------------------
  1320. void LPasswordField::SetVisibleFromHidden(void)
  1321. {    CharsHandle        theHnd;
  1322.     char            *theChar;
  1323.     short            i, theLen;
  1324.  
  1325.  
  1326.  
  1327.     // Find out how much text is in the off screen TextEdit record
  1328.     theHnd = ::TEGetText(mTextEditH);
  1329.     ::HLock(theHnd);
  1330.     theChar    = *theHnd;
  1331.     theLen    = (*mTextEditH)->teLength;
  1332.     
  1333.     
  1334.     // Set the text of the on screen TextEdit record to match the offscreen
  1335.     ::TESetText(theChar, theLen, mBulletTextEditH);
  1336.     
  1337.     
  1338.     // Unclock the text handle of the off screen TextEdit record
  1339.     ::HUnlock(theHnd);
  1340.  
  1341.     
  1342.     // Convert the text of the on screen record to bullets
  1343.     SetTextToBullets(mBulletTextEditH);
  1344. }
  1345.